# -*- coding: utf-8 -*-
from Tix import * # should come with pyton installation: http://wiki.python.org/moin/Tix
import tkFileDialog, tkMessageBox, webbrowser, os.path
from nltk.corpus import *
from lex2toolbox import *
from myToolbox import *
from config import *


def initializeGUI():
    global root 
    root = Tk()
    root.title('NLP Applications: Syntactic lexicons')
    mainMenu(root).pack(side=TOP, fill=X)    
    
    # -- TABS:
    global nb
    nb = NoteBook(root, name='nb', ipadx=6, ipady=6, width=500, height=300)
    nb.add('conversion', label="Conversion")
    nb.add('errorcheck', label="Error checking")
    nb.add('analysis', label="Analysis")
    nb.add('search', label="Search")
    nb.add('fusion', label="Fusion")
    nb.add('extraction', label='Extraction') 
    nb.add('output', label='Output')   
    nb.pack(expand=1, fill=BOTH, padx=5, pady=5 ,side=TOP)

    # -- BUILD PAGES:
    conversionPage(nb.conversion).pack(side=TOP, padx=2, pady=2, fill=X, expand=0) 
    conversionButtons(nb.conversion).pack(side=BOTTOM, padx=15, pady=15, fill=X, expand=0)
    analysisPage(nb.analysis).pack(side=TOP, padx=2, pady=2, fill=BOTH, expand=1)
    analysisButtons(nb.analysis).pack(side=BOTTOM, padx=15, pady=15, fill=X, expand=0)
    searchPage(nb.search).pack(side=TOP, padx=2, pady=2, fill=BOTH, expand=1)
    searchButtons(nb.search).pack(side=BOTTOM, padx=15, pady=15, fill=X, expand=0)
    errorcheckPage(nb.errorcheck).pack(side=TOP, padx=2, pady=2, fill=BOTH, expand=1)
    errorcheckButtons(nb.errorcheck).pack(side=BOTTOM, padx=15, pady=15, fill=X, expand=0)
    fusionPage(nb.fusion).pack(side=TOP, padx=2, pady=2, fill=BOTH, expand=1)   
    fusionButtons(nb.fusion).pack(side=BOTTOM, padx=15, pady=15, fill=X, expand=0)
    extractionPage(nb.extraction).pack(side=TOP, padx=2, pady=2, fill=BOTH, expand=1)
    extractionButtons(nb.extraction).pack(side=BOTTOM, padx=15, pady=15, fill=X, expand=0)
    outputPage(nb.output).pack(side=TOP, padx=2, pady=2, fill=BOTH, expand=1)

def mainMenu(anchor):
    w = Frame(anchor, bd=2, relief=RAISED)
    file = Menubutton(w, text='Menu', takefocus=0)
    file.pack(side=LEFT)
    fm = Menu(file, tearoff=0)
    file['menu'] = fm
    fm.add_command(label='Exit', underline=1,command = quit )
    return w

#-- PAGES -------------------------------------------------------------------------
#-- CONVERSION PAGE
def conversionPage(tab):
    f = Frame(tab)
    
    global sourceFile; sourceFile = StringVar()
    makeFileEntry(f, 'Source file:', (lambda:openFileDialog(sourceFile)), textvariable=sourceFile).pack(side=TOP, anchor=W)
    
    global sourceFormat; sourceFormat = StringVar()
    options = {'treelex':'Treelex', 'synlex':'SynLex', 'lexschem':'Lexschem'}
    makeDropDown(f, 'Source format:', options, variable=sourceFormat).pack(side=TOP, anchor=W)
       
    global targetFile; targetFile = StringVar()
    makeFileEntry(f, 'Target file (tb):', (lambda:saveAsDialog(targetFile)), textvariable=targetFile).pack(side=TOP, anchor=W)
    
    return f

def conversionButtons(tab):
    f = Frame(tab)
    Button(f, text='Convert', command=convertLexicon).pack(side=RIGHT)
    return f

#-- ERROR CHECKING PAGE
def errorcheckPage(tab):
    f = Frame(tab)
    
    global checkSource; checkSource = StringVar()
    makeFileEntry(f, 'Lexicon (tb):', (lambda:openFileDialog(checkSource)), textvariable=checkSource).pack(side=TOP, anchor=W)

    global checkTarget; checkTarget = StringVar()
    makeFileEntry(f, 'Error log:', (lambda:saveAsDialog(checkTarget)), textvariable=checkTarget).pack(side=TOP, anchor=W)
    
    global checkFormat; checkFormat = StringVar()
    options = {'text': 'Toolbox (text)', 'xml':'XML', 'html':'HTML'}
    makeDropDown(f, 'Output format:', options, variable=checkFormat).pack(side=TOP, anchor=W)
    
    return f

def errorcheckButtons(tab):
    f = Frame(tab)
    Button(f, text='Find errors', command=checkLexicon).pack(side=RIGHT)
    return f

#-- ANALYSIS PAGE
def analysisPage(tab):
    f = Frame(tab)
    
    global lexiconToAnalyze; lexiconToAnalyze = StringVar()
    makeFileEntry(f, 'Lexicon (tb):', (lambda:openFileDialog(lexiconToAnalyze)), textvariable=lexiconToAnalyze).pack(side=TOP, anchor=W)
        
    return f

def analysisButtons(tab):
    f = Frame(tab)
    Button(f, text='Analyze toolbox lexicon', command=analyzeLexicon).pack(side=RIGHT)
    return f

#-- SEARCH PAGE
def searchPage(tab):
    f = Frame(tab)
    
    global lexiconToSearch; lexiconToSearch = StringVar()
    makeFileEntry(f, 'Lexicon (tb):', (lambda:openFileDialog(lexiconToSearch)), textvariable=lexiconToSearch).pack(side=TOP, anchor=W)
        
    global verbSearch; verbSearch = StringVar()
    v = makeEntry(f, 'Verb (regex):', textvariable=verbSearch)
    Button(v, text = 'List frames', command=searchScfs).pack(side=TOP)
    v.pack(side=TOP, anchor=W)
    
    global scfSearch; scfSearch = StringVar()
    v = makeEntry(f, 'Frame (regex):', textvariable=scfSearch)
    Button(v, text = 'List verbs', command=searchVerbs).pack(side=TOP)
    v.pack(side=TOP, anchor=W)
    
    return f

def searchButtons(tab):
    f = Frame(tab)
    return f

#-- FUSION PAGE
def fusionPage(tab):
    f = Frame(tab)
    
    global lexiconFuse1; lexiconFuse1 = StringVar()
    makeFileEntry(f, 'Lexicon 1 (tb):', (lambda:openFileDialog(lexiconFuse1)), textvariable=lexiconFuse1).pack(side=TOP, anchor=W)
        
    global lexiconFuse2; lexiconFuse2 = StringVar()
    makeFileEntry(f, 'Lexicon 2 (tb):', (lambda:openFileDialog(lexiconFuse2)), textvariable=lexiconFuse2).pack(side=TOP, anchor=W)
        
    global fuseTarget; fuseTarget = StringVar()
    makeFileEntry(f, 'Target file:', (lambda:saveAsDialog(fuseTarget)), textvariable=fuseTarget).pack(side=TOP, anchor=W)

    global fuseFormat; fuseFormat = StringVar()
    options = {'text': 'Toolbox (text)', 'xml':'XML', 'html':'HTML'}
    makeDropDown(f, 'Output format:', options, variable=fuseFormat).pack(side=TOP, anchor=W)
    
    return f

def fusionButtons(tab):
    f = Frame(tab)
    Button(f, text='Fuse lexicons', command=fuseLexicons).pack(side=RIGHT)
    return f

#-- EXPORT PAGE
def extractionPage(tab):
    f = Frame(tab)
    
    global lexiconToExtract; lexiconToExtract = StringVar()
    makeFileEntry(f, 'Lexicon (tb):', (lambda:openFileDialog(lexiconToExtract)), textvariable=lexiconToExtract).pack(side=TOP, anchor=W)    
    
    global verbSearchExtract; verbSearchExtract = StringVar()
    makeEntry(f, 'Filter lemma (regex):', textvariable=verbSearchExtract).pack(side=TOP, anchor=W)

    global extractLemmatize; extractLemmatize = IntVar()
    makeCheckbox(f, 'Lemmatize:', extractLemmatize).pack(side=TOP, anchor=W)
    
    global extractTarget; extractTarget = StringVar()
    makeFileEntry(f, 'Target file:', (lambda:saveAsDialog(extractTarget)), textvariable=extractTarget).pack(side=TOP, anchor=W)
    
    global extractFormat; extractFormat = StringVar()
    options = {'text': 'Toolbox (text)', 'xml':'XML', 'html':'HTML'}
    makeDropDown(f, 'Output format:', options, variable=extractFormat).pack(side=TOP, anchor=W)
        
    return f

def extractionButtons(tab):
    f = Frame(tab)
    Button(f, text='Extract lexicon', command=extractLexicon).pack(side=RIGHT)
    return f

#-- OUTPUT PAGE 
def outputPage(tab):
    f = Frame(tab)
    scrollbar = Scrollbar(f)
    scrollbar.pack(side=RIGHT, fill=Y)
    global output
    output = Text(f, relief = SUNKEN, state=DISABLED)
    output.pack(side = LEFT, fill = BOTH, expand = YES)
    scrollbar.config(command=output.yview)
    return f

#-- CONSTRUCTION FUNCTIONS --------------------------------------------------------
def makeLabel(f, caption,width=15):
    l = Label(f, text=caption,anchor=E, width=width)
    l.pack(side=LEFT, fill=NONE, pady=5, expand=0)
    return f

def makeFileEntry(parent, caption, command, width=45, **options):
    f = Frame(parent)
    makeLabel(f, caption)
    entry = Entry(f, **options)
    entry.config(width=width)
    entry.pack(side=LEFT, padx=10) 
    button = Button(f, text='Browse...', command=command)
    button.pack(side=RIGHT, padx=5)
    return f

def makeEntry(parent, caption, width=25, **options):
    f = Frame(parent)
    makeLabel(f, caption)
    entry = Entry(f, **options)
    entry.config(width=width)
    entry.pack(side=LEFT, padx=10) 
    return f

def makeDropDown(parent, caption, options, **args):
    f = Frame(parent)
    makeLabel(f, caption)
    box = OptionMenu(f,options='label.width  0 label.anchor e menubutton.width 15',**args)
    
    for opt in options.keys():
        box.add_command(opt, label=options[opt])

    box.pack(side=LEFT, anchor=W)
    return f

def makeCheckbox(parent, caption, variable):
    f = Frame(parent)
    makeLabel(f, caption)
    Checkbutton(f, variable=variable).pack(side=TOP, anchor=W, padx=10)
    return f
          
def openFileDialog(var):
    file = tkFileDialog.askopenfile(mode='rb',title='Choose a file...')
    if not file is None: var.set(file.name)

def saveAsDialog(var):
    file = tkFileDialog.asksaveasfilename(title="Save the lexicon as...")
    var.set(file)
    
#-- ACTIONS ----------------------------------------------------------------------
def convertLexicon():
    # read the file, convert it to toolbox and save that in a file
    if not required([sourceFile.get(), targetFile.get(), sourceFormat.get()]): return False
    
    if sourceFormat.get() == 'lexschem':
        lexschem.convert2TB(sourceFile.get(), targetFile.get())
    elif sourceFormat.get() == 'synlex':    
        synlex.convert2TB(sourceFile.get(), targetFile.get())
    elif sourceFormat.get() == 'treelex':
        treelex.convert2TB(sourceFile.get(), targetFile.get())
    else: return False    
    
    viewResult(targetFile.get(), 'Your lexicon has been saved. Do you want to view the file?')

def checkLexicon():
    # read the file, check for errors and save those to a separate file
    if not required([checkSource.get(), checkTarget.get(), checkFormat.get()]): return False
    source = os.path.abspath(checkSource.get())
    target = checkTarget.get()
    
    lexicon = reader.xml(source)
    numEntries = reader.numEntries(lexicon)
    errorLexicon = reader.errorCheck(lexicon)
    numErrors = reader.numEntries(errorLexicon)
    reader.output(errorLexicon, checkFormat.get(), target)

    viewResult(target, '%s entries in original lexicon\n%s errors found and saved\nDo you want to view the errors?' % (numEntries,numErrors))

def analyzeLexicon():
    # produce a report and output to window
    if not required([lexiconToAnalyze.get()]): return False
    source = os.path.abspath(lexiconToAnalyze.get())
    
    lexicon = reader.xml(source)
    numEntries = reader.numEntries(lexicon)
    numVerbs = reader.numVerbs(lexicon)
    numScfs = reader.numScfs(lexicon)
    ratioVerbsScf = round(reader.ratioVerbsScf(lexicon),2)
    ratioScfsVerb = round(reader.ratioScfsVerb(lexicon),2)
    
    report  = 'OUTPUT ANALYZED LEXICON\n\nSource: %s\n' % source
    report += '\nNum of entries:\t\t%s' %numEntries
    report += '\nNum of verbs:\t\t%s' %numVerbs
    report += '\nNum of subcat frames:\t%s' %numScfs
    report += '\nAvg num of verbs/frame:\t%s' %ratioVerbsScf
    report += '\nAvg num of frames/verb:\t%s' % ratioScfsVerb
    
    outputToWindow(report)   
    
def searchVerbs():
    # output a list of verbs to another window
    if not required([lexiconToSearch.get()]): return False
    source = os.path.abspath(lexiconToSearch.get())
    regex = regexNotEmpty(scfSearch.get())
    report = 'RESULT VERB SEARCH\n\nSource:     %s\nScf filter: %s\n' % (source, regex)
    
    verbs = reader.verbs(reader.xml(source), regex)
    report += '\nNumber of results:%s\n' % len(verbs)
    for v in verbs: report += '\n%s' % v
        
    outputToWindow(report)    
    
def searchScfs():
    # output a list of scfs to another window
    if not required([lexiconToSearch.get()]): return False
    source = os.path.abspath(lexiconToSearch.get())
    regex = regexNotEmpty(verbSearch.get())
    report = 'RESULT SCF SEARCH\n\nSource:       %s\nVerb filter:  %s\n' % (source, regex)
    
    scfs = reader.scfs(reader.xml(source), regex)
    report += '\nNumber of results:%s\n' % len(scfs)
    for s in scfs: report += '\n%s' % s
        
    outputToWindow(report)  
      
def fuseLexicons():
    # take two lexicons and produce a new file
    if not required([lexiconFuse1.get(),lexiconFuse2.get(),fuseTarget.get(), fuseFormat.get()]): return False
    source1 = os.path.abspath(lexiconFuse1.get())
    source2 = os.path.abspath(lexiconFuse2.get())
    target = fuseTarget.get()
    
    fusedLexicon = reader.fuse([reader.xml(source1), reader.xml(source2)])
    reader.output(fusedLexicon, fuseFormat.get(), target)
    
    viewResult(target, 'The fused lexicon has been saved.\nDo you want to view the file?')
    
def extractLexicon():
    # take one lexicon and produce a new file
    if not required([lexiconToExtract.get(), extractFormat.get(), extractTarget.get()]): return False
    verbRegex = regexNotEmpty(verbSearchExtract.get())
    source = os.path.abspath(lexiconToExtract.get())
    target = extractTarget.get()
    lemmatize = extractLemmatize.get()
    
    newLexicon = reader.filter(reader.xml(source), verbRegex, lemmatize)
    reader.output(newLexicon, extractFormat.get(), target)

    viewResult(target, 'The new lexicon has been saved.\nDo you want to view the file?')
    
def quit():
    global root
    root.destroy()
    
def viewResult(file, msg):
    answer = tkMessageBox.askquestion('Success', msg)
    if answer == 'yes': webbrowser.open_new_tab(file)

def outputToWindow(msg):
    global output
    output.config(state=NORMAL)
    output.delete(1.0, END)
    output.insert(1.0, msg)
    output.config(state=DISABLED)
    nb.raise_page('output')

def required(vars):
    for var in vars:
        if var == '': tkMessageBox.showerror('Error', 'One or more required fields are empty.'); return False
    return True

def regexNotEmpty(var):
    if var == '': return '.*'
    return var

#-- EXEC: ------------------------------------------------------------------------
if __name__ == '__main__':
    lexschem = LexschemConverter()
    synlex   = SynlexConverter()
    treelex  = TreelexConverter() 
    reader   = LazyCorpusLoader('toolbox', MyExtendedToolboxCorpusReader, MAINPATH, ENCODING)
    initializeGUI()
    root.mainloop()